#!/usr/bin/python3
#-*-coding:utf-8-*-

###############################################################
## Name       : auto_dff.py
## Author     : gaojiaming
## Date       : Mon Sep 25 16:44:59 CST 2023
## Description:
##
##
###############################################################

import sys
import os
import re
import argparse

def input_args_proc():#{{{
  parser = argparse.ArgumentParser(description="argparse info")
  parser.add_argument('-o', action='store_true', default=False, help='open this script')
  parser.add_argument('-d', action='store_true', default=False, help='del auto generate')
  parser.add_argument('-f', help='input name')
  result = parser.parse_args()
  if result.o == True:
      os.system("gvim %s" % __file__)
      sys.exit(0)
  del_gen = 0
  if result.d == True:
      del_gen = 1
  if not result.f:
      raise ValueError("No input file")
  inp_file = result.f
  return inp_file, del_gen
pass#}}}

def del_gen_code(inp_file):#{{{
  tmp_list = []
  shot_en = 0
  with open(inp_file, "r") as hd:
      handle = hd.readlines()
      for line in handle:
          line = line.rstrip()
          if re.search(r"//AUTO_DFF_START", line):
              shot_en = 1
          if shot_en == 0:
              tmp_list.append(line)
          if re.search(r"//AUTO_DFF_END", line):
              shot_en = 0
  return tmp_list
pass#}}}

def gen_dff(name, width, value, type):
  ret  = "//AUTO_DFF_START\n"
  #ret += "{0} #(.WIDTH({1}), .VALUE({2}))\n".format(name, width, value)

  ret += "wire [{0} -1:0]{1}_d ;\n".format(width, name)
  ret += "wire [{0} -1:0]{1}_q ;\n".format(width, name)
  ret += "wire {0}{1}_en;\n".format(" "*(len(width)+7), name)
  if re.search(r"_parity", type):
    ret += "wire {0}{1}_err;\n".format(" "*(len(width)+7), name)
  #ret += "\n"
  ret += "wire [{0} -1:0]{1} = {1}_q;\n".format(width, name)

  if re.search(r"dffre_parity", type):
    ret += "{0} #(.WIDTH({1}), .VALUE({2}))\n".format(type, width, value)
    ret += "u_{0}_dff (\n".format(name)
    ret += "  .clk    (clk),\n"
    ret += "  .rst_n  (rst_n),\n"
    ret += "  .d      ({0}_d),\n".format(name)
    ret += "  .en     ({0}_en),\n".format(name)
    ret += "  .q      ({0}_q),\n".format(name)
    ret += "  .err    ({0}_err)\n".format(name)
    ret += ");\n"
  elif re.search(r"dffr_parity", type):
    ret += "{0} #(.WIDTH({1}), .VALUE({2}))\n".format(type, width, value)
    ret += "u_{0}_dff (\n".format(name)
    ret += "  .clk    (clk),\n"
    ret += "  .rst_n  (rst_n),\n"
    ret += "  .d      ({0}_d),\n".format(name)
    ret += "  .q      ({0}_q),\n".format(name)
    ret += "  .err    ({0}_err)\n".format(name)
    ret += ");\n"
  elif re.search(r"dffre", type) or re.search(r"dffve", type):
    ret += "{0} #(.WIDTH({1}), .VALUE({2}))\n".format(type, width, value)
    ret += "u_{0}_dff (\n".format(name)
    ret += "  .clk    (clk),\n"
    ret += "  .rst_n  (rst_n),\n"
    ret += "  .d      ({0}_d),\n".format(name)
    ret += "  .en     ({0}_en),\n".format(name)
    ret += "  .q      ({0}_q)\n".format(name)
    ret += ");\n"
  elif re.search(r"dffse", type):
    ret += "{0} #(.WIDTH({1}))\n".format(type, width)
    ret += "u_{0}_dff (\n".format(name)
    ret += "  .clk    (clk),\n"
    ret += "  .rst_n  (rst_n),\n"
    ret += "  .d      ({0}_d),\n".format(name)
    ret += "  .en     ({0}_en),\n".format(name)
    ret += "  .q      ({0}_q)\n".format(name)
    ret += ");\n"
  elif re.search(r"dffr", type):
    ret += "{0} #(.WIDTH({1}), .VALUE({2}))\n".format(type, width, value)
    ret += "u_{0}_dff (\n".format(name)
    ret += "  .clk    (clk),\n"
    ret += "  .rst_n  (rst_n),\n"
    ret += "  .d      ({0}_d),\n".format(name)
    ret += "  .q      ({0}_q)\n".format(name)
    ret += ");\n"
  elif re.search(r"dffe", type):
    ret += "{0} #(.WIDTH({1}), .VALUE({2}))\n".format(type, width, value)
    ret += "u_{0}_dff (\n".format(name)
    ret += "  .clk    (clk),\n"
    ret += "  .d      ({0}_d),\n".format(name)
    ret += "  .en     ({0}_en),\n".format(name)
    ret += "  .q      ({0}_q)\n".format(name)
    ret += ");\n"
  else:
    ret += "{0} #(.WIDTH({1}), .VALUE({2}))\n".format(type, width, value)
    ret += "u_{0}_dff (\n".format(name)
    ret += "  .clk    (clk),\n"
    ret += "  .d      ({0}_d),\n".format(name)
    ret += "  .q      ({0}_q)\n".format(name)
    ret += ");\n"
  ret += "//AUTO_DFF_END"
  return ret
pass

def gen_code(inp_file):
  return_list = []
  handle = del_gen_code(inp_file)
  name  = ""
  width = "1"
  value = ""
  type  = "dffre"
  for line in handle:
    name  = ""
    width = "1"
    value = ""
    type  = "dffre"
    res = re.search(r"\/\*\s*AUTO_DFF\s+(\[.*\])?\s*(\w+)\s*(\=\s*.*)?\s+(\w+)?\s+END\s*\*\/", line)
    if res:
      #print(line)
      #get name
      name = res.group(2)
      #get width
      if res.group(1): # [WIDTH]
        tmp   = res.group(1)
        width = re.match(r"\[(.*)\]", tmp).group(1)
        #print(width)
      #get value
      if res.group(3): # =8'h4
        tmp   = res.group(3)
        value = re.match(r"\=\s*(.*)", tmp).group(1)
      elif re.match(r"^\d+$", width):
        value = "{}'h0".format(width)
      elif re.match(r"^\w+$", width):
        value = "{{{0}{{1'b0}}}}".format(width)
      else:
        value = "{{({0}){{1'b0}}}}".format(width) #{(WD-1){1'b0}}
      #get type
      if res.group(4): # dffre
        type = res.group(4)
      return_list.append(line)
      return_list.append(gen_dff(name, width, value, type))
    else:
      return_list.append(line)
  return return_list
pass        

def main():
  return_list = []
  inp_file, del_gen = input_args_proc()
  if del_gen == 1:
    return_list = del_gen_code(inp_file)
  else:
    return_list = gen_code(inp_file)
  for line in return_list:
    print(line)
pass

if __name__ == "__main__":
    main()
